package com.seari.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.seari.enums.DistrictEnums;
import com.seari.mapper.PassengerFlowMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @ClassName PassengerFlowServiceImpl
 * @Description TODO
 * @Author LANDSUS
 * @Date 2021/4/27 15:07
 * @Version 1.0
 */
@Service
@DS("yidian")
public class PassengerFlowServiceImpl implements PassengerFlowService {

    @Autowired
    private PassengerFlowMapper mapper;

    @Autowired
    private WebClient webClient;

    @Autowired
    private AppCacheService appCacheService;

    @Value("${chengYun.host}")
    private String chengYunHost;

    @Value("${chengYun.port}")
    private String chengYunPort;

    @Override
    public List<Map<String, Object>> stationFlow() {
        return mapper.stationFlow();
    }

    @Override
    public List<Map<String, Object>> stationFlowTodayTotal(String type) {
        List<Map<String, Object>> data = mapper.stationFlowTodayTotal(type);
        return data;
    }

    @Override
    public Map totalDate() {
        //{code=200, msg=查询成功！, data={listPassengerflow=[{dayPassengerflow5Min=22768, dayNetPassengerflow=199142, dayPassengerflow=4296081}]}}
        Mono<Map> result =
                webClient.get().uri("http://{host}:{port}/metrotrans/passengerFlow/getDayPassengerflow", chengYunHost, chengYunPort)
                        .retrieve().bodyToMono(Map.class).doOnError(WebClientResponseException.class, err -> {
                            throw new RuntimeException("getDayPassengerflow error，error Message:"+err.getMessage());
                        });
        // {dayPassengerflow5Min=21942, dayNetPassengerflow=187073, dayPassengerflow=4340327}
        // 查询当天总客流(dayPassengerflow)、在网客流(dayNetPassengerflow)、5分钟总客流(dayPassengerflow5Min)
        Map<String,Object> data = (Map)((List)((Map)result.block().get("data")).get("listPassengerflow")).get(0);

        Mono<Map> trainResult =
                webClient.get().uri("http://{host}:{port}/metrotrans/getOnlineTrain", chengYunHost, chengYunPort)
                        .retrieve().bodyToMono(Map.class).doOnError(WebClientResponseException.class, err -> {
                            throw new RuntimeException("getOnlineTrain error，error Message:"+err.getMessage());
                        });
        String trainData = ((Map)trainResult.block().get("data")).get("trainTotal").toString();
        data.put("todayTrainNum",trainData);

        Map<String,Object> trulyInOutPassenger = mapper.trulyInOutPassenger();
        data.put("trulyEnter",trulyInOutPassenger.get("ENTER"));
        data.put("trulyExit",trulyInOutPassenger.get("EXIT"));

        List<Map<String,Object>> limitStationInfo = (List<Map<String,Object>>)appCacheService.getCacheObject("limitStationInfo");
        data.put("limitStationNum",limitStationInfo == null?0:limitStationInfo.size());
        return data;
    }

    @Override
    public List<Map<String, Object>> total4Station(String type) {
        List<Map<String,Object>> stationNumList = new ArrayList<>();
        List<Map<String,Object>> lineNumList = new ArrayList<>();
        List<Map<String, Object>> data = null;
        List<Map<String, Object>> districtTrulyFlow = new ArrayList<>();
        try{
            data = mapper.total4station(type);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("type不符合任何条件,type:"+type);
            return null;
        }
        if("d".equals(type)){
            // 查询站个数
            stationNumList = mapper.queryStationNum("old");
            // 查询线路个数
            lineNumList = mapper.queryLineNum();
            // 查询行政区最近5分钟客流量
            districtTrulyFlow = mapper.districtFlow();
        }

        // 站点今日总客流量添加排名
        if(data == null || data.size() == 0){
            return null;
        }
        if(data.get(0).get("STATION_NAME_CN") != null){

            for (int i = 0 ; i < data.size(); i++) {
                Map<String, Object> item = data.get(i);
                item.put("STATION_NAME_CN",item.get("STATION_NAME_CN").toString().trim());
                List<String> idList = Arrays.asList(item.get("STATION_ID").toString().split(","));
                item.put("MORNING_PEAK_URL",item.get("MORNING_PEAK_URL") == null ? null:item.get("MORNING_PEAK_URL"));
                item.put("STATION_ID",idList);
                item.put("INDEX",i+1);
            }
        }else {
            List<Map<String, Object>> finalStationNumList = stationNumList;
            List<Map<String, Object>> finalLineNumList = lineNumList;
            List<Map<String, Object>> finalDistrictTrulyFlow = districtTrulyFlow;
            data.stream().forEach(item -> {
                if(item.get("DISTRICT_NAME_CN") != null) {
                    String districtName = item.get("DISTRICT_NAME_CN").toString().trim();
                    item.put("DISTRICT_NAME_CN",districtName);
                    // 站个数
                    finalStationNumList.stream().forEach(stationNum -> {
                        if(districtName.equals(stationNum.get("DISTRICT_NAME_CN").toString().trim())){
                            item.put("STATION_NUM",stationNum.get("NUM"));
                        }
                    });
                    // 线路个数
                    finalLineNumList.stream().forEach(lineNum -> {
                        if(districtName.equals(lineNum.get("DISTRICT_NAME_CN").toString().trim())){
                            item.put("LINE_NUM",lineNum.get("NUM"));
                        }
                    });

                    // 区的实时进出站客流
                    finalDistrictTrulyFlow.stream().forEach(lineNum -> {
                        if(districtName.equals(lineNum.get("DISTRICT_NAME_CN").toString().trim())){
                            item.put("ENTER",lineNum.get("ENTER"));
                            item.put("EXIT",lineNum.get("EXIT"));
                        }
                    });
                }else if(item.get("NEW_DISTRICT_NAME_CN") != null) {
                    item.put("NEW_DISTRICT_NAME_CN",item.get("NEW_DISTRICT_NAME_CN").toString().trim());
                }
            });
        }
        return data;
    }

    @Override
    public Map true4District() {
        //最近一小时各区总客流量 / 最近一小时总客流量 * 实时在网客流 = 各区实时在网客流
        Map<String,Integer> result = new HashMap<>();

        // 最近一小时各区总客流量
        List<Map<String, Object>> lastHourDistrict = mapper.lastHourInPassenger4District();

        // 最近一小时总客流量
        Integer lastHourTotal = mapper.lastHourInPassengerTotal();

        // 实时在网客流
        Integer trulyPassenger = mapper.trulyOnLinePassenger();

        lastHourDistrict.stream().forEach(item -> {
            Integer districtTruly = new BigDecimal(item.get("ENTER").toString())
                    .divide(new BigDecimal(lastHourTotal),10,BigDecimal.ROUND_HALF_UP)
                    .multiply(new BigDecimal(trulyPassenger))
                    .setScale(0,BigDecimal.ROUND_HALF_UP).intValue();
            if(item.get("DISTRICT_NAME_CN") != null){
                result.put(item.get("DISTRICT_NAME_CN").toString().trim(),districtTruly);
            }
        });

        return result;
    }

    @Override
    public List<Map<String, Object>> districtFlow() {
        List<Map<String, Object>> data = mapper.districtFlow();
        return data;
    }

    @Override
    public Map true4NewDistrict() {
        //最近一小时各区总客流量 / 最近一小时总客流量 * 实时在网客流 = 各区实时在网客流

        Map<String,Integer> result = new HashMap<>();

        // 最近一小时五大新城+区总客流量
        List<Map<String, Object>> lastHourDistrict = mapper.lastHourInPassenger4NewDistrict();

        // 最近一小时总客流量
        Integer lastHourTotal = mapper.lastHourInPassengerTotal();

        // 实时在网客流
        Integer trulyPassenger = mapper.trulyOnLinePassenger();

        lastHourDistrict.stream().forEach(item -> {
            Integer districtTruly = new BigDecimal(item.get("ENTER").toString())
                    .divide(new BigDecimal(lastHourTotal),10,BigDecimal.ROUND_HALF_UP)
                    .multiply(new BigDecimal(trulyPassenger))
                    .setScale(0,BigDecimal.ROUND_HALF_UP).intValue();
            result.put(item.get("NEW_DISTRICT_NAME_CN").toString().trim(),districtTruly);
        });

        return result;
    }

    @Override
    public Map<String, Object> newDistrictFlow() {
        Map<String,Object> result = new HashMap<>();
        // 查询五大新城+虹桥商务区id
        List<Map<String,Object>> newDistrictList = mapper.newDistrictList();

        for (Map<String, Object> newDistrict : newDistrictList) {
            Map<String,Object> district = new HashMap<>();
            // 根据区id查询对应的实时出入站客流
            List<Map<String,Object>> inOutFlow = mapper.newDistrictStationFlow(newDistrict.get("NEW_DISTRICT_ID").toString());
            inOutFlow.stream().forEach(item -> item.put("STATION_NAME_CN",item.get("STATION_NAME_CN").toString().trim()));

            // 虹桥机场2号航站楼没有统一的最新时间数据，暂时打得补丁
            if(newDistrict.get("NEW_DISTRICT_NAME_CN").toString().trim().contains("商务区")){
                Map<String,Object> hq = mapper.queryHongQiao2();
                inOutFlow.add(hq);
            }

            district.put("flow",inOutFlow);
            result.put(newDistrict.get("NEW_DISTRICT_NAME_CN").toString().trim(),district);
        }
        return result;
    }

    @Override
    public Integer trulyPassengerAllTrain() {
        return mapper.trulyOnLinePassenger();
    }

    @Override
    public List<Map<String, Object>> newDistrictDailyInAndOutFlow(List<Map<String,Object>> weatherList) {
        //根据区名分类天气，
        //将天气数据取平均
        //将对应的天气数据存入对应的区map
        List<Map<String, Object>> data = mapper.newDistrictDailyInAndOutFlow();
        List<Map<String,Object>> hq = new ArrayList<>();
        List<Map<String,Object>> nh = new ArrayList<>();
        List<Map<String,Object>> jd = new ArrayList<>();
        List<Map<String,Object>> qp = new ArrayList<>();
        List<Map<String,Object>> sj = new ArrayList<>();
        List<Map<String,Object>> fx = new ArrayList<>();
        for (Map<String, Object> weather : weatherList) {
            if(DistrictEnums.HQ.getDistrict().contains(weather.get("town").toString().trim())){
                hq.add(weather);
            }else if(DistrictEnums.NH.getDistrict().contains(weather.get("town").toString().trim())){
                nh.add(weather);
            }else if(DistrictEnums.JD.getDistrict().contains(weather.get("town").toString().trim())){
                jd.add(weather);
            }else if(DistrictEnums.QP.getDistrict().contains(weather.get("town").toString().trim())){
                qp.add(weather);
            }else if(DistrictEnums.SJ.getDistrict().contains(weather.get("town").toString().trim())){
                sj.add(weather);
            }else if(DistrictEnums.FX.getDistrict().contains(weather.get("town").toString().trim())){
                fx.add(weather);
            }
        }

        // 解析天气数据
        List<Map<String,Object>> list = new ArrayList<>();
        list.add(null);list.add(null);list.add(null);list.add(null);list.add(null);list.add(null);list.add(null);
        calculationWeather(hq,DistrictEnums.HQ.getIndex(),DistrictEnums.HQ.getDistrictSize(),list);
        calculationWeather(nh,DistrictEnums.NH.getIndex(),DistrictEnums.NH.getDistrictSize(),list);
        calculationWeather(jd,DistrictEnums.JD.getIndex(),DistrictEnums.JD.getDistrictSize(),list);
        calculationWeather(qp,DistrictEnums.QP.getIndex(),DistrictEnums.QP.getDistrictSize(),list);
        calculationWeather(sj,DistrictEnums.SJ.getIndex(),DistrictEnums.SJ.getDistrictSize(),list);
        calculationWeather(fx,DistrictEnums.FX.getIndex(),DistrictEnums.FX.getDistrictSize(),list);

        // 查询站点数
        List<Map<String, Object>> stationList = mapper.queryStationNum("new");

        // 查询区内站id
        List<Map<String, Object>> lineIdList = mapper.queryLineId();

        data.stream().forEach(item -> {
            String name = item.get("NEW_DISTRICT_NAME_CN").toString().trim();
            item.put("NEW_DISTRICT_NAME_CN",name);
            item.put("NEW_DISTRICT_ID",item.get("NEW_DISTRICT_ID").toString().trim());
            item.put("WEATHER",list.get(Integer.valueOf(item.get("NEW_DISTRICT_ID").toString().trim())));

            // 填充区内站点数
            stationList.stream().forEach(station -> {
                if(station.get("NEW_DISTRICT_NAME_CN").toString().trim().equals(name)){
                    item.put("STATION_NUM",station.get("NUM"));
                }
            });
            List<String> lineList = new ArrayList();

            // 填充区内线路id
            lineIdList.stream().forEach(line -> {
                if(line.get("NEW_DISTRICT_NAME_CN").toString().trim().equals(name)){
                    lineList.add(line.get("LINE_ID").toString());
                }
            });

            item.put("LINE_ID",lineList);
        });
        return data;
    }

    private void calculationWeather(List<Map<String, Object>> list,Integer index,Integer size,List<Map<String,Object>> resultList) {
        BigDecimal totalTem = new BigDecimal(0);
        BigDecimal totalPre = new BigDecimal(0);
        BigDecimal totalTewin = new BigDecimal(0);
        BigDecimal totalWin = new BigDecimal(0);
        for (Map<String, Object> item : list) {
            totalTem = totalTem.add(new BigDecimal(item.get("tem").toString()));
            totalPre = totalPre.add(new BigDecimal(item.get("pre_1h").toString()));
            // 风向
            totalTewin = totalTewin.add(new BigDecimal(item.get("win_d_avg_2mi").toString()));
            // 风速
            totalWin = totalWin.add(new BigDecimal(item.get("win_s_avg_2mi").toString()));
        }

        BigDecimal avgTem = totalTem.divide(new BigDecimal(size),0, RoundingMode.HALF_UP);
        BigDecimal pre = totalPre.divide(new BigDecimal(size),0, RoundingMode.HALF_UP);
        BigDecimal avgTewin = totalTewin.divide(new BigDecimal(size),0, RoundingMode.HALF_UP);
        // 平均风速
        BigDecimal avgWin = totalWin.divide(new BigDecimal(size),0, RoundingMode.HALF_UP);

        Map<String,Object> result = new HashMap<>();
        result.put("TEM",avgTem);

        // 解析天气
        if(pre.compareTo(new BigDecimal("0")) == 0){
            result.put("PRE","晴");
        } else if(pre.compareTo(new BigDecimal("0.1")) < 0){
            result.put("PRE","零星小雨");
        } else if (pre.compareTo(new BigDecimal("1.5")) < 0) {
            result.put("PRE","小雨");
        } else if (pre.compareTo(new BigDecimal("6.9")) < 0) {
            result.put("PRE","中雨");
        } else if (pre.compareTo(new BigDecimal("14.9")) < 0) {
            result.put("PRE","大雨");
        } else if (pre.compareTo(new BigDecimal("39.9")) < 0) {
            result.put("PRE","暴雨");
        } else if (pre.compareTo(new BigDecimal("49.9")) < 0) {
            result.put("PRE","大暴雨");
        } else {
            result.put("PRE","特大暴雨");
        }

        // 解析风向
        if(avgTewin.compareTo(new BigDecimal("33")) < 0){
            result.put("TEWIN","北风");
        } else if(avgTewin.compareTo(new BigDecimal("66")) < 0){
            result.put("TEWIN","东北风");
        } else if(avgTewin.compareTo(new BigDecimal("123")) < 0){
            result.put("TEWIN","东风");
        } else if(avgTewin.compareTo(new BigDecimal("156")) < 0){
            result.put("TEWIN","东南风");
        } else if(avgTewin.compareTo(new BigDecimal("213")) < 0){
            result.put("TEWIN","南风");
        } else if(avgTewin.compareTo(new BigDecimal("246")) < 0){
            result.put("TEWIN","西南风");
        } else if(avgTewin.compareTo(new BigDecimal("303")) < 0){
            result.put("TEWIN","西北风");
        } else if(avgTewin.compareTo(new BigDecimal("360")) < 0){
            result.put("TEWIN","北风");
        }

        // 解析风力
        if(avgWin.compareTo(new BigDecimal("0.2")) < 0){
            result.put("WIN","无风");
        } else if(avgWin.compareTo(new BigDecimal("1.5")) < 0){
            result.put("WIN","1级");
        } else if(avgWin.compareTo(new BigDecimal("3.3")) < 0){
            result.put("WIN","2级");
        } else if(avgWin.compareTo(new BigDecimal("5.4")) < 0){
            result.put("WIN","3级");
        } else if(avgWin.compareTo(new BigDecimal("7.9")) < 0){
            result.put("WIN","4级");
        } else if(avgWin.compareTo(new BigDecimal("10.7")) < 0){
            result.put("WIN","5级");
        } else if(avgWin.compareTo(new BigDecimal("13.8")) < 0){
            result.put("WIN","6级");
        } else if(avgWin.compareTo(new BigDecimal("17.1")) < 0){
            result.put("WIN","7级");
        }

        resultList.add(index,result);
    }

    @DS("chengyun")
    public List<Map<String,Object>> queryNewDistrictWeather(){
        return mapper.queryNewDistrictWeather();
    }

    @Override
    public List<Map<String, Object>> jinBo() {
        // 线路id,站名,站点id,今日总,实时进出站客流
        List<String> stationNameList = new ArrayList<>();
        stationNameList.add("虹桥火车站");
        stationNameList.add("徐泾东");
        stationNameList.add("诸光路");
        // 线路id,站点id,站点中文名
        List<Map<String,Object>> stationIdList = mapper.queryStationIdByStationName(stationNameList);
        // 线路id集合
        List<Integer> idList = new ArrayList<>();
        // 站名---线路id
        Map<String,Object> stationNameLineIdMap = new HashMap<>();
        // 整理出站点id集合，根据中文名将线路id存入
        stationIdList.stream().forEach(item -> {
            idList.add(Integer.valueOf(item.get("STATION_ID").toString().trim()));
            List<Integer> id = new ArrayList<>();
            if(stationNameLineIdMap.get(item.get("STATION_NAME_CN")) != null){
                id = (List)stationNameLineIdMap.get(item.get("STATION_NAME_CN"));
            }
            id.add(Integer.valueOf(item.get("LINE_ID").toString()));
            stationNameLineIdMap.put(item.get("STATION_NAME_CN").toString().trim(),id);
        });
        // 站点id，实时进出站客流，站点名称
        List<Map<String, Object>> inAndOutFlow = mapper.queryInAndOutFlowByStationId(idList);

        // 今日总,站点名称，站点id
        List<Map<String, Object>> totalFlow = mapper.queryTotalFlowByStationId(idList);

        List<Map<String,Object>> result = new ArrayList<>();
        inAndOutFlow.stream().forEach(item -> {
            String stationNameCn = item.get("STATION_NAME_CN").toString().trim();
            Map<String,Object> otherMap = new HashMap<>();
            otherMap.put("STATION_ID",item.get("STATION_ID"));
            otherMap.put("STATION_NAME_CN",stationNameCn);
            otherMap.put("ENTER",item.get("ENTER"));
            otherMap.put("EXIT",item.get("EXIT"));
            otherMap.put("LINE_ID",stationNameLineIdMap.get(stationNameCn));
            result.add(otherMap);
        });
        totalFlow.stream().forEach(item -> {
            String stationNameCn = item.get("STATION_NAME_CN").toString().trim();
            result.stream().forEach(element -> {
                if(element.get("STATION_NAME_CN").equals(stationNameCn)){
                    element.put("TOTAL_FLOW",item.get("TOTAL"));
                    element.put("TOTAL_ENTER",item.get("ENTER"));
                    element.put("TOTAL_EXIT",item.get("EXIT"));
                }
            });
        });
        return result;
    }

    @Override
    public List<Map<String, Object>> queryStationByStationId(List<String> stationList) {
        return mapper.queryStationByStationId(stationList);
    }

    @Override
    public List<Map<String, Object>> monitor(List<String> stationNameList) {
        // 线路id,站点id,站点中文名
        List<Map<String,Object>> stationIdList = mapper.queryStationIdByStationName(stationNameList);
        List<String> idList = new ArrayList<>();
        stationIdList.stream().forEach(item -> idList.add(item.get("STATION_ID").toString().trim()));
        List<Map<String, Object>> result = queryStationByStationId(idList);
        return result;
    }

    @Override
    public List<Map<String, Object>> monitor6station() {
        // 线路id,站名,站点id,今日总,实时进出站客流
        List<String> stationNameList = new ArrayList<>();
        stationNameList.add("人民广场");
        stationNameList.add("南京东路");
        stationNameList.add("江苏路");
        stationNameList.add("莘庄");
        stationNameList.add("徐家汇");
        stationNameList.add("虹桥火车站");
        return monitor(stationNameList);
    }
}
